package gss;

import org.apache.commons.math.fraction.BigFraction;
import java.math.BigInteger;


import java.io.Reader;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.InputStreamReader;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Scanner;
import java.util.Set;

import static gss.generator.GeneratorUtils.*;


public class GSSToGraph {
    
    private static final String FRAC_REGEX = "(\\d+)(\\s*/\\s*(\\d+))?";
    public static String reduce = null;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws FileNotFoundException, IOException {
	
        // Process CLI arguments for INPUT ONLY	
        Scanner scanner = null;
        String input_file = null;
        String gss_file = null;
        String matrix_file = null;
        String vertex_file = null;
     

        try {
            if(args.length < 5){
        	System.err.println("incorrect number of arguments");
        	System.err.println("inputfile outputfile O/S");
            }
            else{
                    reduce = args[0];
                    input_file = args[1]; 
                    scanner = new Scanner(new BufferedReader(new FileReader(input_file)));
                    gss_file = args[2];
                    matrix_file = args[3];
                    vertex_file = args[4];
                                       
            }
            
            // declare some temporary variables
	    String num = null, denom = null;
	    BigFraction frac = null;
	    
	    ArrayList<LineSegment> linesegs = new ArrayList<LineSegment>();
	    ArrayList<LineSegment> edges = new ArrayList<LineSegment>();
	    ArrayList<Vertex> vertices = new ArrayList<Vertex>();

            // read in all data from file
            while (scanner.hasNext()) {
                Scanner line_scanner = new Scanner(scanner.nextLine());
                java.util.regex.MatchResult matcher = null;
                
                ArrayList<BigFraction> endpoints = new ArrayList<BigFraction>();
                
		while (null != line_scanner.findInLine(FRAC_REGEX)) {
		    matcher = line_scanner.match();
		    num = matcher.group(1);
		    denom = matcher.group(3);
		    if (denom == null || denom.equals("")) {
			denom = "1";
		    }
		    frac = new BigFraction(new BigInteger(num), new BigInteger(denom));
		    endpoints.add(frac);
		}
		
		linesegs.add(new LineSegment(endpoints.get(0), 
			endpoints.get(1), endpoints.get(2), endpoints.get(3) ));		
            }
            //add all of the edges and vertices for each segment
            for(LineSegment seg : linesegs){
        	addSegment(seg, linesegs, edges, vertices );
            }
            
            //print the gss, matrix and vertex files
            writeFiles(edges, vertices, gss_file, matrix_file, vertex_file);
        
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            if (scanner != null) {
                scanner.close();
            }
        }
    }//end main
    
    //takes a line segment, divides it into edges and adds the edges and 
    // the vertices to their corresponding sets
    public static void addSegment(LineSegment segment, Collection<LineSegment> segments,
	    Collection<LineSegment> edges, List<Vertex> vertices){
	ArrayList<Vertex> intersections = new ArrayList<Vertex>();
	
	//finds all intersection points
	for(LineSegment l : segments){
	    if (!segment.isParallelTo(l) && segment.intersects(l)) {
		Vertex tempvert = segment.intersectionPoint(l);
		addVertex(tempvert, intersections);
	    }
	}
	
	//if arg2 is "S", no extra edges are added with endpoints of the segment
	// unless the line segment intersects only one other
	if(reduce.equals("S") && intersections.size()==1){
	    Vertex v1 = segment.getVertex1();
	    Vertex v2 = segment.getVertex2();
	    if(!v1.equals(intersections.get(0))){
		addVertex(v1, intersections);
	    }
	    else{
		addVertex(v2, intersections);
	    }	    
	}
	// if arg2 is "O", include edges with endpoints of the segment
	if(reduce.equals("O")){
	    addVertex(segment.getVertex1(), intersections);
	    addVertex(segment.getVertex2(), intersections);
	}
	
	if(segment.isNotVertical()){
	    Collections.sort(intersections, new Vertex.XComparator());
	}
	else{
	    Collections.sort(intersections, new Vertex.YComparator());
	}
		
	for(int i = 0; i < intersections.size()-1; i++){
	    //add the edges
	    LineSegment edge = new LineSegment(
		    intersections.get(i), intersections.get(i+1));
	    edges.add(edge);
	    
	    //add the vertices
	    HashSet<LineSegment> visible = new HashSet<LineSegment>();
	    visible.add(edge);
	    
	    Vertex v1 = new Vertex(intersections.get(i).getX(),
		    intersections.get(i).getY());
	    v1.mergeVisibility(visible);
	    
	    Vertex v2 = new Vertex(intersections.get(i+1).getX(),
		    intersections.get(i+1).getY());
	    v2.mergeVisibility(visible);
	    
	    addVertex(v1, vertices);
	    addVertex(v2, vertices);
	}	
    }

    
    
    
}//end class
